import javax.swing.*;
import java.io.*;
import java.text.*;

public class CommandManager implements Serializable {

	CommandBuilder CommandBuilder = new CommandBuilder();
	private enum CmdList {SAVE, BUY, SELL, QUEST, QUESTS, QUESTLOG, INSPECT, EXAMINE, TAKE, GO, SLEEP, USE, PUT, STATS, PLACE, HELP, DRINK, EAT, CONSUME, SPEAK, TALK, DROP, GIVE, LOOT, KILL, SEARCH, GET, DEBUG, ASK, ATTACK, OPEN, EQUIP, UNEQUIP, NULL }
	private GUI Gui;
	private GameState gameState;
	private DecimalFormat df = new DecimalFormat("#.#");
	
	public void setBattleMan(GUI a) {
		Gui = a;
	}

	
	public void ParseCmd(String input, Player player, JTextArea y, JTextArea x, InventoryWindow z, JTextField p) {
		
		String Input = input;
		
		CmdList Cmd = CmdList.NULL;
		
		CommandBuilder.init(Input);
		
		String Command = CommandBuilder.getCommand();
		String Target = CommandBuilder.getTarget();
		String Orientation = CommandBuilder.getOrientation();
		String Place = CommandBuilder.getPlace();
		
		try {
		for (CmdList a : CmdList.values()) {
			if (a.toString().equalsIgnoreCase(Command)) {
				Cmd = a;
			} 
		}
		} catch (IndexOutOfBoundsException e) {
			y.append("Please type a command.");
		}
		
		if (player.isCorpse == true) {
			y.append("You are dead! Please start a new game or load a previous save.");
		} else {
					
		
		switch (Cmd) {
		
		case GIVE:
			if (Place.equalsIgnoreCase("")) {
				y.append("Please specify who you want to give an item to.");
			} else if (Target.equalsIgnoreCase("")) {
				y.append("Please specify what you want to give.");
			} else {
			player.giveObject(Target, Place, y, z);
			player.addActionCount();
			}
		break;
		
		case INSPECT:
		case EXAMINE:
		if (!Target.equalsIgnoreCase("")) {
			if (Orientation == null) {	
				try {
				player.Examine(Target, y);
				} catch (NullPointerException e) {
					y.append("You can't see an object matching that description." + "\n");
				}
			} else {
				try {
					player.ExamineSpecific(player.getCurrentLocation().findSpecificObject(Target, Orientation, Place, player), y);
					player.addActionCount();
				} catch (NullPointerException e) {
					y.append("You can't see a " + Target + " in that location." + "\n");
				}
			}
		} else {
			y.append("Please specify what it is you wish to " + Command + ".");
		}
			
			break;
		case SELL:
			Entity Solditem = player.findItemInInventory(Target);
			Character buyingMerchant = player.getCurrentLocation().findMerchant();
			try {
				player.Sell(Solditem, buyingMerchant, y);
			} catch (NullPointerException e) {
				y.append("You don't have an item matching that description!");
			}
			break;
		case BUY:
			Entity item = player.getCurrentLocation().findObject(Target);
			Character merchant = player.getCurrentLocation().findMerchant();
			try {
				if (item.isForSale() == true) {
						player.Buy(item, merchant, y);
				} else {
					y.append("This item isn't for sale!");
				}
			} catch (NullPointerException e) {
				y.append("You can't see an item matching that description!");
			}
			break;
		case GET:
		case TAKE:
			if (!Target.equalsIgnoreCase("")) {
				if (Orientation == null) {		
					try {
						if (player.getCurrentLocation().findObject(Target).isForSale() == true) {
							y.append("This item is for sale in a shop and belongs to the merchant, you can BUY this item from them, or STEAL it.");
						} else {
							player.takeItem(Target, y, z);
							player.addActionCount();
						}
					} catch (NullPointerException e) {
						y.append("You can't see an object matching that description." + "\n");
					}
				} else {
					try {
						if (player.getCurrentLocation().findSpecificObject(Target, Orientation, Place, player).isForSale() == true) {
							y.append("This item is for sale in a shop and belongs to the merchant, you can BUY this item from them, or STEAL it.");
						} else {
							player.takeSpecific(player.getCurrentLocation().findSpecificObject(Target, Orientation, Place, player), player.getCurrentLocation().findObject(Place), y);
							player.addActionCount();
						}
					} catch (NullPointerException e) {
						y.append("You can't see a " + Target + " in that location.");
					}
				}
			
			} else {
				y.append("Please specify what it is you wish to " + Command + ".");
			}
			
			break;
			
		case GO:
		if (!Target.equalsIgnoreCase("")) {	
			try {
				player.useExit(Target, y, x);
				player.addActionCount();
				} catch (NullPointerException e) {
					y.append("You cannot go that way!" + "\n");
				}
		} else {
			y.append("Please specify where it is you wish to " + Command + ".");
		}
			break;	
		
		case SLEEP:
			for (Entity a : player.getCurrentLocation().getInventory()) {
				if (a.isBed() == true) {
					if (player.canSleep() == true) {
						player.Sleep(true);
						y.append("You lie down on the " + a.getName() + " and close your eyes...");
						player.setLastSlept(player.ActionsPerformed());
						
					} else {
						y.append("You have already slept recently and don't feel tired, try again later.");
					}
					break;
				} else {
					
				}
				
			}
			if (player.isAsleep() == false) {
				y.append("You cannot see a suitable place to sleep here.");
			}
			break;
		case USE:
			if (Target.contains("bed") || Target.contains("cot")) {
				if (player.getCurrentLocation().findObject(Target) == null) {
					y.append("You can't see a bed in this location, or one matching that description.");
				} else {
					if (player.canSleep() == true) {
						player.Sleep(true);
						y.append("You climb into the " + player.getCurrentLocation().findObject(Target).getName() + " and close your eyes...");	
						player.setLastSlept(player.ActionsPerformed());
					} else {
						y.append("You have already slept recently and don't feel tired. Try again later.");
					}
				}
			} else {
				try {
					if (player.findItemInInventory(Target).getName().equalsIgnoreCase("toomany")) {
						y.append("You have more than one item in your inventory matching that description, please be more specific." + "\n");
					} else if (Place == null ) {
						y.append("Please specify what you wish to use the '" + Target + "' on.\n\n");
					}
					player.useItem(player.findItemInInventory(Target), Place, y, p);
					player.addActionCount();
					}
				catch (NullPointerException e) {
					y.append("You don't have that object!!!" + "\n");
				}
			}
			break;
			
		case HELP:
			
			if (Target.equalsIgnoreCase("General")) {
				y.append("* Use EXAMINE, TAKE, SEARCH, OPEN to interact with objects in your vicinity.\n");
				y.append("* Use TAKE or GET to pick up an item and store it in your inventory.\n");
				y.append("* You can specify exact locations e.g 'Examine key on table', 'examine knife in inventory'.\n");
				y.append("* Use DROP to drop an item in your inventory on the floor.\n");
				y.append("* The USE command will use an item in your inventory on an object in the environment, e.g 'use key on door'\n");
			} else {
				y.append("Guide:\n\n");
				y.append("Type 'help' followed by one of the below choices to get help on that topic:\n");
				y.append("GENERAL\n");
				y.append("COMBAT\n");
				y.append("CONVERSATION or TRADE\n");
				y.append("ABILITIES or STATS\n");
				y.append("QUESTS");
			}
			break;
		
		case PUT:
		case PLACE:
			try {
				if (!Orientation.equalsIgnoreCase("") || Orientation.equalsIgnoreCase("Empty") || Orientation.equals(null)) {
					try {
						player.Put(player.findItemInInventory(Target), player.getCurrentLocation().findObject(Place), (Orientation.substring(0, 1).toUpperCase() + Orientation.substring(1)), y);
						player.addActionCount();
					} catch (NullPointerException e) {
						y.append("You can't see an object matching that description.");
					}
				}
			} catch (NullPointerException e) {
					y.append("You can only put items on, in or under other objects.");
			}
			break;
			
		case DROP:
			
			player.dropItem(Target, y, z);
			player.addActionCount();
			break;
		
		case SEARCH:
		case OPEN:	
		case LOOT:
			
			try {
				Entity target = player.getCurrentLocation().findObject(Target);
				if (target.getClass().getName().equalsIgnoreCase("Character") && target.isVisible() == true) {
					player.lootCharacter(Target, y);
					player.addActionCount();
				} else if (!target.getClass().getName().equalsIgnoreCase("Character") && target.isVisible() == true){
					player.lootObject(Target, y);
					player.addActionCount();
				}		
			} catch (NullPointerException e) {
				y.append("You can't see an object matching that description.");
			}
			break;
			
		case KILL:
			
			try {
				if (player.getCurrentLocation().findCharacter(Target).isCorpse() == false) {
				player.getCurrentLocation().findCharacter(Target).Death();
				player.addActionCount();
				} else {
					y.append("It's already dead!");
				}
			} catch (NullPointerException e) {
				y.append("You can't see anyone matching that description.");
			}
			break;
			
		case DEBUG:
			
			y.append("Debug stats:\n\n");
			y.append("Current player location: " + player.getCurrentLocation().getDisplayName());
			break;
			
		case ASK:
			
			try {
				player.speak(y, player.getCurrentLocation().findCharacter(Target), Place, player);
				player.addActionCount();
			} catch (NullPointerException e) {
				y.append("You can't see anyone matching that description");
			}	
			break;
			
		case ATTACK:
			
			try {
				if (player.getCurrentLocation().findCharacter(Target).isCorpse() == false) {
					player.setCurrentOpponent(player.getCurrentLocation().findCharacter(Target));
					player.getCurrentLocation().findCharacter(Target).modifyDisposition(-1000);
					Gui.getBattleMan().engage(player, player.getCurrentOpponent(), "player");
					player.addActionCount();
				} else {
					y.append("The " + player.getCurrentLocation().findCharacter(Target).getName() + " is already dead!");
				}
			} catch (NullPointerException e) {
				y.append("You can't see anyone matching that description.");
			}
			
			break;
			
		case EQUIP:
			
			try {
			y.append("You equip the " + player.findItemInInventory(Target).getName() + ".\n");
			player.equip(Target);
			player.addActionCount();
			} catch (ClassCastException e) {
				y.append("You can't equip that!");
			} catch (NullPointerException e) {
				y.append("You don't have an item matching that description.");
			}
			break;
		
		case UNEQUIP:
			
			player.unequip(Target);
			player.addActionCount();
			break;
		
		case EAT:
		case CONSUME:
		case DRINK:
			try {
			player.findConsumableInInventory(Target).consume(player, y);
			player.removeObject(player.findConsumableInInventory(Target));
			player.addActionCount();
			} catch (NullPointerException e) {
				y.append("You don't have anything edible matching that description!");
			}
			break;
		case QUEST:
		case QUESTS:
		case QUESTLOG:
			player.printQuests(y);
			break;
		case STATS:
			y.append("Current stats:\n\n");
			y.append("Chance to hit: " + df.format(player.ChanceToHit(player.get_Main_Hand().getWeaponType())) + "%\n");
			y.append("Chance to dodge: " + df.format(player.ChanceToDodge()) + "%\n");
			y.append("Chance to parry: " + df.format(player.ChanceToParry(player.get_Main_Hand().getWeaponType())) + "%\n\n");
			y.append("Current status effects:\n\n");
			for (StatusEffect a : player.getEffects()) {
				y.append(a.getName() + ": ");
				if (a.getPenalty("Endurance") != 0) {
					y.append("End " + a.getPenalty("Endurance"));
				}
				if (a.getPenalty("Strength") != 0) {
					y.append("Str " + a.getPenalty("Strength"));
				}
				if (a.getPenalty("Agility") != 0) {
					y.append("Agi " + a.getPenalty("Agility"));
				}
				if (a.getPenalty("Intelligence") != 0) {
					y.append("Int " + a.getPenalty("Intelligence"));
				}
				if (a.getPenalty("Willpower") != 0) {
					y.append("Wil " + a.getPenalty("Willpower"));
				}
				if (a.getPenalty("Health") != 0) {
					y.append("HP " + a.getPenalty("Health") + " (per tick)");
				}
				y.append("\n");
			}
			
			break;
			
		case SAVE:
			String filename = ("C:\\saves\\" + Target + ".sav");
			FileOutputStream fos = null;
			ObjectOutputStream out = null;
			     try
			     {
			       fos = new FileOutputStream(filename);
			       out = new ObjectOutputStream(fos);
			       out.writeObject(gameState);
			       out.close();
			     }
			     catch(IOException ex)
			     {
			       ex.printStackTrace();
			     }
			break;
		default:
			y.append("Invalid Command! Use HELP for a list of valid commands.\n\n");
			break;
		}
		
	z.Refresh(player);
	
	}
	}
	
	public void setGameState(GameState a) {
		gameState = a;
	}
	
	public GameState getGameState() {
		return gameState;
	}
	
}
